"""
用户端API - 小说列表和详情
"""
import os
import shutil

from fastapi import APIRouter, Query, HTTPException, Header, Form, UploadFile, File
from pydantic import BaseModel
from typing import Optional, List
from tortoise.models import Model

from app.page.lx import main
from models.m import Novel, Chapter, NovelCategory, AuthorVerification, AuthorVerificationStatus, User
from tortoise.expressions import Q
from tool.jwt_utils import verify_token, get_current_user
from tool.sessing import Settings

page_user = APIRouter()






# ==================== 响应模型 ====================

class NovelListItem(BaseModel):
    """小说列表项"""
    id: int
    title: str
    author: str
    cover_url: Optional[str] = None
    description: Optional[str] = None
    category_name: str
    word_count: int
    chapter_count: int
    view_count: int
    collect_count: int
    rating: float
    status: str
    is_featured: bool
    tags: Optional[List[str]] = None
    
    class Config:
        from_attributes = True


class ChapterListItem(BaseModel):
    """章节列表项"""
    id: int
    title: str
    chapter_number: int
    word_count: int
    view_count: int
    is_vip: bool
    
    class Config:
        from_attributes = True


class NovelDetailResponse(BaseModel):
    """小说详情响应"""
    id: int
    title: str
    author: str
    cover_url: Optional[str] = None
    description: Optional[str] = None
    category_name: str
    tags: Optional[List[str]] = None
    status: str
    word_count: int
    chapter_count: int
    view_count: int
    collect_count: int
    rating: float
    is_vip: bool
    chapters: List[ChapterListItem]
    
    class Config:
        from_attributes = True


# ==================== 小说列表接口 ====================

@page_user.get("/novels", summary="获取小说列表", tags=["小说"])
async def get_novel_list(
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(10, ge=1, le=100, description="每页数量"),
    category_id: Optional[int] = Query(None, description="分类ID"),
    keyword: Optional[str] = Query(None, description="搜索关键词"),
    status: Optional[int] = Query(None, description="状态（1-连载中，2-已完结）"),
    is_featured: Optional[bool] = Query(None, description="是否推荐")
):
    """
    获取小说列表
    
    - 支持分页
    - 支持按分类筛选
    - 支持关键词搜索
    - 支持按状态筛选
    - 支持推荐筛选
    """
    try:
        # 构建查询条件
        query = Novel.filter(audit_status=2)  # 只返回审核通过的
        
        if category_id:
            query = query.filter(category_id=category_id)
        
        if status:
            query = query.filter(status=status)
        
        if is_featured is not None:
            query = query.filter(is_featured=is_featured)
        
        if keyword:
            # 关键字同时匹配 书名/作者/简介
            query = query.filter(
                Q(title__icontains=keyword) |
                Q(author__icontains=keyword) |
                Q(description__icontains=keyword)
            )
        
        # 获取总数
        total = await query.count()
        
        # 分页查询
        novels = await query.order_by('-created_at')\
                           .offset((page - 1) * page_size)\
                           .limit(page_size)\
                           .prefetch_related('category')
        
        # 转换为响应模型
        novel_list = []
        for novel in novels:
            novel_list.append(NovelListItem(
                id=novel.id,
                title=novel.title,
                author=novel.author,
                cover_url=novel.cover_url,
                description=novel.description,
                category_name=novel.category.name,
                word_count=novel.word_count,
                chapter_count=novel.chapter_count,
                view_count=novel.view_count,
                collect_count=novel.collect_count,
                rating=float(novel.rating),
                status="连载中" if novel.status == 1 else "已完结",
                is_featured=novel.is_featured,
                tags=novel.tags
            ))
        
        return {
            "code": 200,
            "message": "获取成功",
            "data": {
                "list": novel_list,
                "pagination": {
                    "total": total,
                    "page": page,
                    "page_size": page_size,
                    "total_pages": (total + page_size - 1) // page_size
                }
            }
        }
    
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取小说列表失败: {str(e)}")


# ==================== 小说详情接口 ====================

@page_user.get("/novels/{novel_id}", summary="获取小说详情", tags=["小说"])
async def get_novel_detail(novel_id: int):
    """
    获取小说详情
    
    - 包含小说基本信息
    - 包含所有章节列表
    """
    try:
        # 获取小说
        novel = await Novel.get_or_none(id=novel_id).prefetch_related('category')
        
        if not novel:
            raise HTTPException(status_code=404, detail="小说不存在")
        
        # 检查是否审核通过
        if novel.audit_status != 2:
            raise HTTPException(status_code=403, detail="小说未通过审核")
        
        # 获取章节列表
        chapters = await Chapter.filter(novel_id=novel_id)\
                               .order_by('chapter_number')\
                               .all()
        
        chapter_list = []
        for chapter in chapters:
            chapter_list.append(ChapterListItem(
                id=chapter.id,
                title=chapter.title,
                chapter_number=chapter.chapter_number,
                word_count=chapter.word_count,
                view_count=chapter.view_count,
                is_vip=chapter.is_vip
            ))
        
        # 构建响应
        return {
            "code": 200,
            "message": "获取成功",
            "data": {
                "id": novel.id,
                "title": novel.title,
                "author": novel.author,
                "cover_url": novel.cover_url,
                "description": novel.description,
                "category_name": novel.category.name,
                "tags": novel.tags,
                "status": "连载中" if novel.status == 1 else "已完结",
                "word_count": novel.word_count,
                "chapter_count": novel.chapter_count,
                "view_count": novel.view_count,
                "collect_count": novel.collect_count,
                "rating": float(novel.rating),
                "is_vip": novel.is_vip,
                "chapters": chapter_list
            }
        }
    
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取小说详情失败: {str(e)}")


# ==================== 章节内容接口 ====================

@page_user.get("/novels/{novel_id}/chapters/{chapter_id}", summary="获取章节内容", tags=["小说"])
async def get_chapter_content(novel_id: int, chapter_id: int):
    """
    获取章节内容
    
    - 返回完整的章节文本内容
    """
    try:
        # 获取章节
        chapter = await Chapter.get_or_none(id=chapter_id, novel_id=novel_id)
        
        if not chapter:
            raise HTTPException(status_code=404, detail="章节不存在")
        
        # 检查章节是否审核通过
        if chapter.audit_status != 2:
            raise HTTPException(status_code=403, detail="章节未通过审核")
        
        # 返回章节内容
        return {
            "code": 200,
            "message": "获取成功",
            "data": {
                "id": chapter.id,
                "novel_id": novel_id,
                "title": chapter.title,
                "chapter_number": chapter.chapter_number,
                "content": chapter.content,
                "word_count": chapter.word_count,
                "is_vip": chapter.is_vip
            }
        }
    
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取章节内容失败: {str(e)}")


# ==================== 分类列表接口 ====================

@page_user.get("/categories", summary="获取分类列表", tags=["小说"])
async def get_categories():
    """
    获取所有小说分类
    """
    try:
        categories = await NovelCategory.filter(is_active=True).all()
        
        category_list = []
        for cat in categories:
            # 获取该分类下的小说数量
            novel_count = await Novel.filter(category_id=cat.id, audit_status=2).count()
            
            category_list.append({
                "id": cat.id,
                "name": cat.name,
                "slug": cat.slug,
                "description": cat.description,
                "novel_count": novel_count
            })
        
        return {
            "code": 200,
            "message": "获取成功",
            "data": category_list
        }
    
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取分类列表失败: {str(e)}")


# ==================== 我的作品列表 ====================

@page_user.get("/my/novels", summary="获取当前作者的作品列表", tags=["小说"])
async def get_my_novels(authorization: str | None = Header(None)):
    """
    根据 Authorization Bearer token 解析当前用户ID，返回其名下作品列表。
    返回字段与前端作者页表格对齐：id、title、category_name、status、audit_status、
    word_count、view_count、collect_count、is_featured。
    """
    try:
        if not authorization or not authorization.lower().startswith("bearer "):
            raise HTTPException(status_code=401, detail="未授权：缺少Bearer Token")

        token = authorization.split(" ", 1)[1].strip()
        payload = verify_token(token)
        if not payload or not payload.get("user_id"):
            raise HTTPException(status_code=401, detail="无效或过期的Token")

        user_id = payload["user_id"]

        novels = await Novel.filter(user_id=user_id).order_by("-updated_at").prefetch_related("category")

        items = []
        for n in novels:
            items.append({
                "id": n.id,
                "title": n.title,
                "category_name": n.category.name if n.category_id else "",
                "status": int(n.status),
                "audit_status": int(n.audit_status),
                "word_count": n.word_count,
                "view_count": n.view_count,
                "collect_count": n.collect_count,
                "is_featured": n.is_featured,
            })

        return {
            "code": 200,
            "message": "获取成功",
            "data": {
                "list": items,
                "total": len(items)
            }
        }

    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取我的作品失败: {str(e)}")



#作者申请表
@page_user.post("/register", summary="注册作者", tags=["用户"])
async def register_author(real_name: str = Form(...),
    id_card: str = Form(...),
    pen_name: str = Form(...),
    introduction: Optional[str] = Form(None),
    sample_work: Optional[str] = Form(None),
    id_card_front_file: UploadFile = File(...),
    id_card_back_file: Optional[UploadFile] = File(None),
    authorization: str | None = Header(None)):
    """
    注册作者接口

    Args:
        real_name: 真实姓名
        id_card: 身份证号
        pen_name: 笔名
        introduction: 作者简介
        sample_work: 作品样例
        id_card_front_file: 身份证正面照片文件
        id_card_back_file: 身份证反面照片文件（可选）

    Returns:
        注册结果
    """

    # 1. 验证Token并获取用户
    if not authorization or not authorization.lower().startswith("bearer "):
        raise HTTPException(status_code=401, detail="未授权：缺少Bearer Token")

    token = authorization.split(" ", 1)[1].strip()
    user_id = get_current_user(token)
    if not user_id:
        raise HTTPException(status_code=401, detail="无效或过期的Token")

    user = await User.get_or_none(id=user_id)
    if not user:
        raise HTTPException(status_code=404, detail="用户不存在")

    # 2. 检查是否已提交过申请
    existing_verification = await AuthorVerification.get_or_none(user_id=user_id)

    if existing_verification:
        raise HTTPException(status_code=400, detail="该用户已提交过作者认证申请")

    # 3. 校验文件格式和大小
    allowed_extensions = {'.jpg', '.jpeg', '.png'}
    front_ext = os.path.splitext(id_card_front_file.filename)[1].lower()
    if front_ext not in allowed_extensions:
        raise HTTPException(status_code=400, detail="身份证正面照片格式不支持，仅支持jpg/png")

    # 检查文件大小（最大5MB）
    max_size = 5 * 1024 * 1024
    if id_card_front_file.size and id_card_front_file.size > max_size:
        raise HTTPException(status_code=400, detail="身份证正面照片文件过大，最大5MB")

    # 4. 创建认证记录
    verification = AuthorVerification(
        user_id=user_id,
        real_name=real_name,
        id_card=id_card,
        pen_name=pen_name,
        introduction=introduction,
        sample_work=sample_work,
        status=AuthorVerificationStatus.PENDING
    )

    # 5. 处理身份证正面照片
    front_filename = f"{real_name}_{id_card}_正面_{user_id}.jpg"
    front_path = os.path.join(Settings.IMAGE_DIR, front_filename)
    
    try:
        # 确保目录存在
        os.makedirs(Settings.IMAGE_DIR, exist_ok=True)
        
        # 保存文件
        with open(front_path, "wb") as buffer:
            shutil.copyfileobj(id_card_front_file.file, buffer)

        # 设置URL
        verification.id_card_front_url = f"/tool/img/{front_filename}"

        # 6. OCR识别身份证正面
        try:
            img_result = main(front_filename)
            if not img_result or "words_result" not in img_result:
                raise HTTPException(status_code=400, detail="身份证正面OCR识别失败：无法解析结果")
            
            # 验证姓名是否匹配
            name_info = img_result.get("words_result", {}).get("姓名", {})
            ocr_name = name_info.get("words", "").strip() if name_info else ""
            
            if not ocr_name:
                raise HTTPException(status_code=400, detail="身份证正面照片中未识别到姓名")
            
            if ocr_name != real_name:
                raise HTTPException(status_code=400, detail=f"身份证姓名({ocr_name})与提交姓名({real_name})不符")
                
        except HTTPException:
            raise
        except Exception as e:
            # OCR失败时清理已上传文件
            if os.path.exists(front_path):
                os.remove(front_path)
            raise HTTPException(status_code=400, detail=f"身份证正面OCR识别失败: {str(e)}")

    except Exception as e:
        # 文件保存失败时清理
        if os.path.exists(front_path):
            os.remove(front_path)
        raise HTTPException(status_code=500, detail=f"处理身份证正面照片失败: {str(e)}")

    # 7. 处理身份证反面照片（可选）
    if id_card_back_file:
        back_ext = os.path.splitext(id_card_back_file.filename)[1].lower()
        if back_ext not in allowed_extensions:
            raise HTTPException(status_code=400, detail="身份证反面照片格式不支持，仅支持jpg/png")
        
        if id_card_back_file.size and id_card_back_file.size > max_size:
            raise HTTPException(status_code=400, detail="身份证反面照片文件过大，最大5MB")

        back_filename = f"{real_name}_{id_card}_反面_{user_id}.jpg"
        back_path = os.path.join(Settings.IMAGE_DIR, back_filename)
        
        try:
            with open(back_path, "wb") as buffer:
                shutil.copyfileobj(id_card_back_file.file, buffer)
            verification.id_card_back_url = f"/tool/img/{back_filename}"
        except Exception as e:
            # 反面照片失败不影响主流程，但记录错误
            print(f"保存身份证反面照片失败: {str(e)}")

    # 8. 保存到数据库
    await verification.save()

    return {
        "code": 200,
        "message": "作者认证申请提交成功",
        "data": {"verification_id": verification.id}
    }







